/*
 * katjushaBoardsReader.java
 *
 * Created on 2009/05/29 +0900
 *
 * $Revision: 132 $
 * $Date: 2010-11-22 09:52:40 +0000 (Mon, 22 Nov 2010) $
 */

package org.gikolet.ch2.android.io;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.input.CountingInputStream;
import org.apache.commons.io.input.TeeInputStream;
import org.gikolet.ch2.data.Board;
import org.gikolet.ch2.data.Category;
import org.gikolet.ch2.io.BoardsReader;
import org.gikolet.ch2.io.Storage;
import org.gikolet.ch2.logic.Ch2Exception;
import org.gikolet.ch2.logic.NotModifiedException;
import org.gikolet.util.IOUtils;
import org.gikolet.util.Tuple.Tuple2;

/**
 * @author tetsutaro (latest modification by $Author: zh1bvtan1 $)
 * @version $Revision: 132 $
 */
public class RemoteKatjushaBoardsReader implements BoardsReader {

	private File file;
	private File tmpFile;

	private KatjushaBoardsStreamParser parser;

	private CountingInputStream countHttpIn;

	private HttpURLConnection http;

	private boolean error = false;
	private boolean end = false;

	public RemoteKatjushaBoardsReader(URL url, boolean cache, Storage storage,
			String charsetName) throws IOException {
		this(url, cache, storage, Charset.forName(charsetName));
	}

	public RemoteKatjushaBoardsReader(URL url, boolean cache, Storage storage,
			Charset charset) throws IOException {

		this.file = storage.getBoardFile();
		// 適当
		this.tmpFile = File.createTempFile("tmp", ".brd", storage
				.getTempDirectory());

		OutputStream fileOut = null;
		InputStream httpIn = null;

		try {

			this.http = (HttpURLConnection) url.openConnection();
			this.http.setRequestMethod("GET");

			if (cache && this.file.isFile()) {
				this.http.setIfModifiedSince(this.file.lastModified());
			}

			this.http.connect();

			int resCode = this.http.getResponseCode();

			switch (resCode) {
			case HttpURLConnection.HTTP_NOT_MODIFIED:
				throw new NotModifiedException("Http response code is +304.");

			case HttpURLConnection.HTTP_OK:
				break;

			default:
				throw new Ch2Exception("responce code(=" + resCode
						+ ") is invalid");
			}

			this.countHttpIn = new CountingInputStream(this.http
					.getInputStream());

			httpIn = this.countHttpIn;

			fileOut = new BufferedOutputStream(new FileOutputStream(
					this.tmpFile, true));

			httpIn = new TeeInputStream(httpIn, fileOut, true);

			this.parser = new KatjushaBoardsStreamParser(httpIn, charset);

		} catch (IOException e) {
			IOUtils.closeQuietly(httpIn);
			IOUtils.closeQuietly(fileOut);

			throw e;
		}
	}

	public long getContentLength() {
		long cl = this.http.getContentLength();
		if (cl != -1) {
			return this.file.length() + this.http.getContentLength();
		}
		return -1;
	}

	public long getReadContentLength() {
		return this.parser.getReadContentLength();
	}

	public Tuple2<Category, List<Board>> read() throws IOException {
		try {
			Tuple2<Category, List<Board>> categoryBoards = this.parser.read();
			if (categoryBoards == null) {
				this.end = true;
			}
			return categoryBoards;

		} catch (IOException e) {
			this.error = true;
			throw e;

		} catch (RuntimeException e) {
			this.error = true;
			throw e;

		} catch (Error e) {
			this.error = true;
			throw e;
		}
	}

	public void close() throws IOException {
		try {
			this.parser.close();

			if (!this.error && this.end) {
				FileUtils.moveFile(this.tmpFile, this.file);

				if (this.http.getLastModified() != 0) {
					this.file.setLastModified(this.http.getLastModified());
				}

			} else {
				this.tmpFile.delete();
			}

		} finally {
			this.http.disconnect();
		}
	}
}
